/*
 * Connection.java   0.0.1    28/set/2009
 * 
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */ 
package org.mentalsmash.tazio.net.cs.client;

import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;


/**
 * This is the interface that clients should use to send messages to a 
 * RemoteServer. A concrete instance of this interface abstracts a connection to a
 * server, and <strong>does not</strong> manage possible disconnections, or
 * server switching.
 * <p>
 * Basically it provides two patterns of use:
 * <ol>
 *   <li>
 *     A <strong>synchronous</strong> interaction: use {@link #sendRequest(Serializable)}
 *     to send a message to the server and wait for its response
 *   </li>
 *   <li>
 *     An <strong>asynchronous</strong> interaction: use {@link #sendRequestAsync(Serializable)}
 *     to send a message to the server and continue. The response can be retrievet at any time
 *     by polling the returned {@link Future} object.
 *    </li> 
 * </ol>
 * </p>
 * @author Andrea Reale <andrea.reale@gmail.com
 * @version 0.0.1
 * @see RemoteServer
 */
public interface Connection {
    
    /**
     * Send an asynchronous request message to the server, and do <strong>not</strong>
     * wait for the response.
     * <p>
     * The response can later be retrieved using the {@link Future} reference returned
     * as the outcome of this methods 
     * </p>
     * <p>
     * Notice that if any exception is thrown while asynchronously executing this method
     * you will not be notified, until you invoke {@link Future#get()} on the returned
     * object. At this time - If any exception occurred - you will receive an 
     * {@link ExecutionException}, having as <code>cause</code> the original exception.
     * </p>
     * @param request any serializable object representing a request for the server
     * @return a {@link Future} handle that can be used to poll the response once it
     *         is available
     * @throws ConnectionStateException if this method is called while this connection
     *                                  is not valid
     * @see #isValid()
     */
    Future<Serializable> sendRequestAsync(Serializable request) 
    	throws IOException, ConnectionStateExeption;
    
    /**
     * Send a synchronous request message to the server. The thread that calls this 
     * method will block until a response (in the form of a serializable object) is
     * returned from the server.
     * <p>
     * The thread that invokes this method will perform itself
     * the actual writing and reading from the underlying connection
     * </p>
     * @param request any serializable object representing a request for the server
     * @return the response from the server, as a serializable object
     * @throws IOException if problems with the underlying communication mechanism
     *                     (e.g. sockets) occur
     * @throws ConnectionStateException if this method is called while this connection
     *                                  is not valid
     * @see #isValid()
     */
    Serializable sendRequest(Serializable request) throws IOException, ConnectionStateExeption;
    
    /**
     * Send a message to the server. Use this method if no response is expected for the
     * message sent. 
     * <p>
     * This method is executed asynchronously hence the method returns immediately
     * without waiting for message to be sent. Nevertheless the dispatching of the message
     * can fail, and an exception may be thrown for the thread that is actually sending the message.
     * You can check whether this method threw an exception or not by calling {@link Future#get()}
     * on the returned future instance: <br/>
     * If any exception occurred while sending the message an {@link ExecutionException} will be
     * rose at this point, bearing as its cause the originial exception. <br />
     * Otherwise {@link Future#get()} should return {@link RequestStatus#OK}.
     * </p>
     * @param message the message to be sent
     * @return an instance of {@link Future} to check the outcome of this method
     * @throws ConnectionStateExeption if this method is called while this connection
     *                                  is not valid
     */
    Future<RequestStatus> sendMessageAsync(Serializable message) throws  ConnectionStateExeption;
    
    /**
     * Send a message to the server. Use this method if no response is expected for the
     * message sent.
     * <p>
     * This is the synchronous version of {@link #sendMessageAsync(Serializable)}. <br/>
     * </p>
     * <p>
     * The thread that invokes this method will perform itself
     * the actual writing and reading from the underlying connection
     * </p>
     * @param message  the message to be sent
     * @throws IOException if an I/O error occurs.
     * @throws ConnectionStateExeption  if this method is called while this connection
     *                                  is not valid
     */
    void sendMessage(Serializable message) throws IOException, ConnectionStateExeption;
    
    
    /**
     * Get the {@link RemoteServer} instance associated with this <tt>Connection</tt> or
     * <code>null</code> if currently not connected.
     * @return the {@link RemoteServer} instance associated with this <tt>Connection</tt>
     */
    RemoteServer getRemoteServer();
    
    /**
     * Checks whether this connection instance is still valid. I.E. it checks
     * if it is associated with a valid {@link RemoteServer} that is in the 
     * <i>Connected State</i>
     * @return true if this connection instance is valid.
     * @see RemoteServer
     */
    boolean isValid();
    
    /**
     * Closes the connection and its related resources.
     * <p>
     * This method also cleans the status in the related
     * {@link RemoteServer} instance.
     * </p>
     */
    void close();
    
    public enum RequestStatus {
	OK,
	EXCEPTION_OCCURRED;
    }

    
}
